home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TeX 1995 July
/
TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO
/
dviware
/
dvipage
/
fonts.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-05-11
|
31KB
|
1,336 lines
/*
* dvipage: DVI Previewer Program for Suns
*
* Neil Hunt (hunt@spar.slb.com)
*
* This program is based, in part, upon the program dvisun,
* distributed by the UnixTeX group, extensively modified by
* Neil Hunt at the Schlumberger Palo Alto Research Laboratories
* of Schlumberger Technologies, Inc.
*
* Copyright (c) 1988 Schlumberger Technologies, Inc 1988.
* Anyone can use this software in any manner they choose,
* including modification and redistribution, provided they make
* no charge for it, and these conditions remain unchanged.
*
* This program is distributed as is, with all faults (if any), and
* without any warranty. No author or distributor accepts responsibility
* to anyone for the consequences of using it, or for whether it serves any
* particular purpose at all, or any other reason.
*
* $Log: fonts.c,v $
* Revision 1.1 88/11/28 18:40:54 hunt
* Initial revision
*
* Stripped out of dvipage 1.4,
* with additions from mitdrivers from TeX 1988 distribution tape.
*/
#include <stdio.h>
#include <sys/param.h> /* For MAXPATHLEN */
#include <fcntl.h>
#include <suntool/sunview.h>
#include "dvipage.h"
#include "dvi.h"
forward FILE * open_font_file();
forward bool init_font_file();
forward bool read_font_char();
static int nopen = 0; /* number of open FNT files */
/*
* get_font_def:
* Read the font definitions as they are in the postamble of the DVI file.
* Returns TRUE unless the document can not be processed further.
*/
bool
get_font_def()
{
char *calloc ();
unsigned char byte;
while(((byte = get_unsigned(dvifp, 1)) >= FNT_DEF1) &&
(byte <= FNT_DEF4))
{
switch (byte)
{
case FNT_DEF1:
if(! read_font_def(get_unsigned(dvifp, 1)))
return FALSE;
break;
case FNT_DEF2:
if(! read_font_def(get_unsigned(dvifp, 2)))
return FALSE;
break;
case FNT_DEF3:
if(! read_font_def(get_unsigned(dvifp, 3)))
return FALSE;
break;
case FNT_DEF4:
if(! read_font_def(get_unsigned(dvifp, 4)))
return FALSE;
break;
default:
message(
"%s: Bad dvi file: bad font specification.", filename);
return FALSE;
}
}
if(byte != POST_POST)
{
message(
"%s: Bad dvi file: no postpostamble after fontdefs.", filename);
return FALSE;
}
return TRUE;
}
/*
* skip_font_def:
* Ignore font definition when fonts have been read from the postamble.
*/
/* ARGSUSED */
void
skip_font_def(k)
int k;
{
int a, l;
(void)get_unsigned(dvifp, 4);
(void)get_unsigned(dvifp, 4);
(void)get_unsigned(dvifp, 4);
a = get_unsigned(dvifp, 1);
l = get_unsigned(dvifp, 1);
fseek(dvifp, (long)a+l, 1);
}
/*
* read_font_def:
* Reads font def, and attempts to open font file and read data.
* Returns TRUE unless a fatal error has occurred so that
* document processing cannot proceed.
*/
bool
read_font_def(k)
int k;
{
int i;
struct char_entry *tcharptr;
FILE *font_fp;
/*
* Allocate and link new font entry.
*/
if((fontptr =
(struct font_entry *)calloc(1, sizeof(struct font_entry))) == NULL)
{
message(
"Out of memory for font entries; try a larger machine.");
return FALSE;
}
fontptr->next = hfontptr;
hfontptr = fontptr;
/*
* Fill in new font entry.
*/
fontptr->font_file_fd = NULL;
fontptr->k = k;
fontptr->c = get_unsigned(dvifp, 4); /* checksum */
fontptr->s = get_unsigned(dvifp, 4); /* space size */
fontptr->d = get_unsigned(dvifp, 4); /* design size */
fontptr->a = get_unsigned(dvifp, 1); /* area length for font name */
fontptr->l = get_unsigned(dvifp, 1); /* device length */
fread(fontptr->n, 1, fontptr->a+fontptr->l, dvifp);
fontptr->n[fontptr->a+fontptr->l] = '\0';
fontptr->font_space = fontptr->s/6; /* never used */
fontptr->font_gf_mag = (int)((actual_factor((int)(((float)fontptr->s/
(float)fontptr->d)*1000.0 + 0.5)) *
#ifdef USEGLOBALMAG
actual_factor(mag) *
#endif
(float)resolution) + 0.5);
fontptr->font_pxl_mag = (int)((actual_factor((int)(((float)fontptr->s/
(float)fontptr->d)*1000.0 + 0.5)) *
#ifdef USEGLOBALMAG
actual_factor(mag) *
#endif
(float)resolution * 5.0) + 0.5);
/*
* Try to find the font file to match.
*/
if(! find_font_file(font_path, fontptr) ||
(font_fp = open_font_file(fontptr)) == NO_FILE)
{
message("Cant find or open font file \"%s\" .%dgf or .%dpxl",
fontptr->n, fontptr->font_gf_mag, fontptr->font_pxl_mag);
if(verbose & DEBUG_FONTS)
fprintf(stderr,
"Cant find font file %s %s .%dgf or .%dpxl\n",
font_path, fontptr->n,
fontptr->font_gf_mag, fontptr->font_pxl_mag);
fontptr->font_file_fd = NO_FILE;
fontptr->magnification = 0;
fontptr->designsize = 0;
for(i = 0; i < NFNTCHARS; i++)
{
tcharptr = &(fontptr->ch[i]);
tcharptr->width = 0;
tcharptr->height = 0;
tcharptr->xOffset = 0;
tcharptr->yOffset = 0;
tcharptr->where.isloaded = FALSE;
tcharptr->where.address.fileOffset = NONEXISTENT;
tcharptr->tfmw = 0;
}
return TRUE;
}
else
return init_font_file(font_fp, fontptr);
}
/*
* open_font_file:
* Called with fontptr; opens a file for this font.
* May have to close another to do it.
* Returns a FILE * pointer, or NO_FILE.
*/
FILE *
open_font_file(fontptr)
struct font_entry *fontptr;
{
register struct font_entry *tfontptr, *lufontptr;
register int used;
if(nopen >= MAXOPEN)
{
used = MAXINT;
lufontptr = NULL;
for(tfontptr = hfontptr; tfontptr; tfontptr = tfontptr->next)
{
if(tfontptr->font_file_fd == NO_FILE ||
tfontptr->font_file_fd == NULL ||
tfontptr == fontptr)
continue;
if(tfontptr->use_count < used)
{
used = tfontptr->use_count;
lufontptr = tfontptr;
}
}
if(lufontptr == NULL)
{
fprintf(stderr, "Cant have no least used font\n");
exit(1);
}
if(verbose & DEBUG_FONTS)
fprintf(stderr, "Closing (%x) font '%s'\n",
lufontptr->font_file_fd, lufontptr->name);
fclose(lufontptr->font_file_fd);
lufontptr->font_file_fd = NULL;
--nopen;
}
/*
* Open the file; close-on-exec.
*/
if((fontptr->font_file_fd = fopen(fontptr->name, "r")) == NULL)
{
message("Cant open font file %s", fontptr->name);
fontptr->font_file_fd = NO_FILE;
}
else
{
if(verbose & DEBUG_FONTS)
fprintf(stderr, "Opened (%x) font '%s'\n",
fontptr->font_file_fd, fontptr->name);
fcntl(fileno(fontptr->font_file_fd), F_SETFD, 1);
nopen++;
}
return fontptr->font_file_fd;
}
/*
* close_fonts:
* Closes all the font files, and frees up all the memory.
*/
void
close_fonts()
{
register struct font_entry *pf, *next;
register struct pixrect *pr;
register int i;
for(pf = hfontptr; pf; pf = next)
{
if(verbose & DEBUG_FONTS)
fprintf(stderr, "Freeing font %s\n", pf->name);
/*
* Close the file if still open.
*/
if(pf->font_file_fd != NO_FILE && pf->font_file_fd != NULL)
{
fclose(pf->font_file_fd);
--nopen;
}
pf->font_file_fd = NULL;
/*
* Free the pixrects.
*/
for(i = 0; i < NFNTCHARS; i++)
{
if(pf->ch[i].where.isloaded == TRUE)
{
if(pr = pf->ch[i].where.address.pixrectptr)
pr_destroy(pr);
}
}
/*
* Get the next.
*/
next = pf->next;
free(pf);
}
hfontptr = NULL;
fontptr = NULL;
if(nopen != 0)
{
fprintf(stderr, "Mislaid some font files; cant happen\n");
exit(1);
}
}
/*
* load_char:
* Reads in a character from the font file.
* Returns TRUE unless document cannot be processed.
*/
bool
load_char(fontptr, ptr)
struct font_entry *fontptr;
struct char_entry *ptr;
{
register FILE *font_fp;
if(verbose & DEBUG_CHARS)
fprintf(stderr, "Load char %d of font %s at offset %d\n",
(ptr - &fontptr->ch[0]), fontptr->name,
ptr->where.address.fileOffset);
/*
* If the font file is currently unopen, then open it.
*/
if((font_fp = fontptr->font_file_fd) == NULL)
font_fp = open_font_file(fontptr);
/*
* If the font file is unavailable, forget it.
*/
if(font_fp == NO_FILE)
{
ptr->where.isloaded = TRUE;
return TRUE;
}
/*
* Read the font character.
*/
return read_font_char(font_fp, fontptr, ptr);
}
/*
* Generic Font reading functions.
* ==============================
*/
forward bool init_gf_font_file();
forward bool init_pxl_font_file();
forward bool init_pk_font_file();
forward bool read_gf_font_char();
forward bool read_pxl_font_char();
forward bool read_pk_font_char();
/*
* init_font_file:
* Reads general data from font file.
* Returns TRUE unless processing cannot continue.
*/
bool
init_font_file(font_fp, fontptr)
FILE *font_fp;
struct font_entry *fontptr;
{
switch(fontptr->type)
{
case TYPE_GF:
return init_gf_font_file(font_fp, fontptr);
case TYPE_PXL:
return init_pxl_font_file(font_fp, fontptr);
case TYPE_PK:
return init_pk_font_file(font_fp, fontptr);
default:
fprintf(stderr, "Unknown type of font file; cant happen\n");
exit(1);
}
}
/*
* read_font_char:
* Reads character from font file.
* Returns TRUE unless document cannot be processed.
*/
bool
read_font_char(font_fp, fontptr, ptr)
FILE *font_fp;
struct font_entry *fontptr;
struct char_entry *ptr;
{
switch(fontptr->type)
{
case TYPE_GF:
return read_gf_font_char(font_fp, fontptr, ptr);
case TYPE_PXL:
return read_pxl_font_char(font_fp, fontptr, ptr);
case TYPE_PK:
return read_pk_font_char(font_fp, fontptr, ptr);
default:
fprintf(stderr, "Unknown type of font file; cant happen\n");
exit(1);
}
}
/*
* GF font reading functions.
* ==========================
*/
#define false 0
#define true 1
/* The following macros describe gf file format */
#define paint_0 0
#define last_paint 63
#define paint1 64
#define paint2 65
#define paint3 66
#define boc 67
#define boc1 68
#define eoc 69
#define skip0 70
#define skip1 71
#define skip2 72
#define skip3 73
#define new_row_0 74
#define last_new_row 238
#define xxx1 239
#define xxx2 240
#define xxx3 241
#define xxx4 242
#define yyy 243
#define no_op 244
#define char_loc 245
#define char_loc0 246
#define pre 247
#define post 248
#define postpost 249
#define undefined_cases 250: case 251: case 252: case 253: case 254: case 255
#define gf_version 131
/*
* init_gf_font_file:
* Reads font data from file.
* If the file is unavailable, its fp is set to NO_FILE.
* Returns TRUE unless processing cannot continue.
*/
bool
init_gf_font_file(font_fp, fontptr)
FILE *font_fp;
struct font_entry *fontptr;
{
register int b, c;
register struct char_entry *tcharptr;
long checksum; /* should match TFM file and DVI file */
long hppp, vppp; /* horizontal and vertical pixels/point scaled
* 1<<16 */
int font_min_m, font_max_m, font_min_n, font_max_n;
int char_wd; /* character width in pixels, rounded if
* necessary */
/*
* Seek to the postamble part of the GF file.
*/
fseek(font_fp, -5L, 2); /* skip four 223's */
do
{
c = get_unsigned(font_fp, 1);
fseek(font_fp, -2L, 1);
} while(c == 223);
if(c != gf_version)
{
message("Bad GF font version number (%d) in %s.",
c, fontptr->name);
fclose(fontptr->font_file_fd);
fontptr->font_file_fd = NO_FILE;
return TRUE;
}
fseek(font_fp, -3L, 1); /* back up to the pointer */
if(fseek(font_fp, (long)get_unsigned(font_fp, 4), 0) < 0 ||
get_unsigned(font_fp, 1) != post)
{
message("Bad GF font file format in %s.", fontptr->name);
fclose(fontptr->font_file_fd);
fontptr->font_file_fd = NO_FILE;
return TRUE;
}
(void)get_unsigned(font_fp, 4); /* ignore back pointer to font-wide xxx
* commands */
fontptr->designsize = get_unsigned(font_fp, 4);
checksum = get_unsigned(font_fp, 4);
hppp = get_unsigned(font_fp, 4);
vppp = get_unsigned(font_fp, 4);
font_min_m = get_unsigned(font_fp, 4);
font_max_m = get_unsigned(font_fp, 4);
font_min_n = get_unsigned(font_fp, 4);
font_max_n = get_unsigned(font_fp, 4);
if(verbose & DEBUG_FONTS)
fprintf(stderr, "Initialising font %s\n", fontptr->name);
for(tcharptr = &fontptr->ch[0]; tcharptr < &fontptr->ch[NFNTCHARS];
tcharptr++)
{
tcharptr->where.isloaded = FALSE;
tcharptr->where.address.fileOffset = -1;
tcharptr->tfmw = 0;
}
for(;;)
{
b = get_unsigned(font_fp, 1);
c = get_unsigned(font_fp, 1);
if(verbose & DEBUG_CHARS)
fprintf(stderr, "Finding char %d type %d\n", c, b);
if(b == char_loc0)
char_wd = get_unsigned(font_fp, 1);
else if(b == char_loc)
{
char_wd = (get_unsigned(font_fp, 4) + 0100000) >> 16;
get_unsigned(font_fp, 4); /* skip dy */
}
else
break;
tcharptr = &(fontptr->ch[c % NFNTCHARS]);
tcharptr->tfmw =
((float)get_unsigned(font_fp, 4) * (float)fontptr->s) /
(float)(1 << 20);
tcharptr->where.address.fileOffset = get_unsigned(font_fp, 4);
}
if((fontptr->c != 0) && (checksum != 0) && (fontptr->c != checksum))
message("Bad font checksum %d != %d, font %s.",
checksum, fontptr->c, fontptr->name);
/*
* Return leaving font file open for use.
*/
return TRUE;
}
/*
* read_font_char:
* Reads character from font file.
* Returns TRUE unless document cannot be processed.
*/
bool
read_gf_font_char(font_fp, fontptr, ptr)
FILE *font_fp;
struct font_entry *fontptr;
register struct char_entry *ptr;
{
register int i, b, c;
register int x, y;
register struct pixrect *pr;
int min_m, max_m, min_n, max_n;
int bytes, lines, paint_switch;
long backpointer;
long charfam;
if(verbose & DEBUG_CHARS)
fprintf(stderr, "Reading char %d of font %s\n",
(ptr - &fontptr->ch[0]), fontptr->name);
/*
* Seek to start of char.
*/
fseek(font_fp, (long)ptr->where.address.fileOffset, 0);
/*
* Sync with char
*/
do
{
switch(i = get_unsigned(font_fp, 1))
{
case yyy:
(void)get_unsigned(font_fp, 1);
/* FALLTHROUGH */
case paint3:
case skip3:
(void)get_unsigned(font_fp, 1);
/* FALLTHROUGH */
case paint2:
case skip2:
(void)get_unsigned(font_fp, 1);
/* FALLTHROUGH */
case paint1:
case skip1:
(void)get_unsigned(font_fp, 1);
break;
case boc:
case boc1:
break;
case pre:
if((c = get_unsigned(font_fp, 1)) != gf_version)
{
message(
"Bad GF font version number (%d); font %s.",
c, fontptr->name);
return TRUE;
}
fseek(font_fp, (long)get_unsigned(font_fp, 1), 1);
break;
case xxx1:
fseek(font_fp, (long)get_unsigned(font_fp, 1), 1);
break;
case xxx2:
fseek(font_fp, (long)get_unsigned(font_fp, 2), 1);
break;
case xxx3:
fseek(font_fp, (long)get_unsigned(font_fp, 3), 1);
break;
case xxx4:
fseek(font_fp, (long)get_unsigned(font_fp, 4), 1);
break;
case post:
if(verbose & DEBUG_FONTS)
fprintf(stderr, "gettochar: found POST\n");
return TRUE;
case char_loc:
case char_loc0:
case postpost:
case undefined_cases:
message(
"Bad GF font file format (%d); font %s.",
i, fontptr->name);
return TRUE;
default: /* do nothing */ ;
break;
}
if(i != boc && i != boc1 &&
verbose & DEBUG_FONTS)
fprintf(stderr, "gettochar iterates with %d\n", i);
}
while(i != boc && i != boc1);
/*
* Read character code and raster sizes.
*/
switch(i)
{
case boc:
c = get_unsigned(font_fp, 4);
backpointer = get_unsigned(font_fp, 4);
min_m = get_unsigned(font_fp, 4);
max_m = get_unsigned(font_fp, 4);
min_n = get_unsigned(font_fp, 4);
max_n = get_unsigned(font_fp, 4);
charfam = c < 0 ? -((-c) >> 8) : c >> 8;
break;
case boc1:
c = get_unsigned(font_fp, 1);
x = get_unsigned(font_fp, 1); /* del_m */
max_m = get_unsigned(font_fp, 1);
min_m = max_m - x;
x = get_unsigned(font_fp, 1); /* del_n */
max_n = get_unsigned(font_fp, 1);
min_n = max_n - x;
break;
default:
fprintf(stderr,
"Font BOC code has corrupted in memory; cant happen.\n");
exit(1);
}
ptr->width = max_m - min_m + 1;
ptr->height = max_n - min_n + 1;
ptr->xOffset = -min_m;
ptr->yOffset = max_n;
/*
* Create Pixrect for char.
* Clear to zero.
*/
pr = mem_create(ptr->width, ptr->height, 1);
ptr->where.address.pixrectptr = pr;
pr_rop(pr, 0, 0, ptr->width, ptr->height, PIX_SRC | PIX_COLOR(0),
NULL, 0, 0);
#ifdef NEVER
pr_rop(pr, 0, 0, ptr->width, ptr->height, PIX_SRC | PIX_COLOR(1),
NULL, 0, 0);
pr_rop(pr, 1, 1, ptr->width-2, ptr->height-2, PIX_SRC | PIX_COLOR(0),
NULL, 0, 0);
#endif NEVER
x = 0;
y = 0;
paint_switch = 0;
for(;;)
{
switch(b = get_unsigned(font_fp, 1))
{
case paint1:
bytes = get_unsigned(font_fp, 1);
goto paint;
case paint2:
bytes = get_unsigned(font_fp, 2);
goto paint;
case paint3:
bytes = get_unsigned(font_fp, 3);
goto paint;
case skip0:
lines = 0;
goto skip;
case skip1:
lines = get_unsigned(font_fp, 1);
goto skip;
case skip2:
lines = get_unsigned(font_fp, 2);
goto skip;
case skip3:
lines = get_unsigned(font_fp, 3);
goto skip;
case xxx1:
fseek(font_fp, (long)get_unsigned(font_fp, 1), 1);
continue;
case xxx2:
fseek(font_fp, (long)get_unsigned(font_fp, 2), 1);
continue;
case xxx3:
fseek(font_fp, (long)get_unsigned(font_fp, 3), 1);
continue;
case xxx4:
fseek(font_fp, (long)get_unsigned(font_fp, 4), 1);
continue;
case yyy:
get_unsigned(font_fp, 4);
continue;
case no_op:
continue;
case eoc:
ptr->where.isloaded = TRUE;
return TRUE;
default:
if(b >= paint_0 && b <= last_paint)
{
bytes = b - paint_0;
paint:; /*
* Paint the specified number of bytes black
* or white.
* Toggle the paint colour.
* Advance the current position.
*/
if(verbose & DEBUG_CHARS)
fprintf(stderr,
" Paint %d line %d, %d for %d\n", paint_switch, y, x, bytes);
if(bytes > 0 && paint_switch)
pr_rop(pr, x, y, bytes, 1,
PIX_SRC | PIX_COLOR(1), NULL, 0, 0);
paint_switch = ! paint_switch;
x += bytes;
continue;
}
else if(b >= new_row_0 && b <= last_new_row)
{
/*
* Special shortcut; skip to new row,
* and paint some white bytes.
* Leave switch ready for next black bytes.
*/
y++;
x = b - new_row_0;
paint_switch = 1;
if(verbose & DEBUG_CHARS)
fprintf(stderr,
" Jump to line %d, paint white to %d\n", y, x);
continue;
}
else
{
message(
"Bad GF file format code %d; char %d font %s.",
b, (ptr - &fontptr->ch[0]), fontptr->name);
return TRUE;
}
skip:; /*
* Skip to the start of the line.th next line.
* Start at beginnning of line, ready to paint white.
*/
y += lines + 1;
x = 0;
paint_switch = 0;
if(verbose & DEBUG_CHARS)
fprintf(stderr,
" Jump to line %d at start\n", y);
continue;
}
}
}
/*
* PXL font reading functions.
* ==========================
*/
#define NPXLCHARS 128
/*
* init_pxl_font_file:
* Reads font data from file.
* If the file is unavailable, its fp is set to NO_FILE.
* Returns TRUE unless processing cannot continue.
*/
bool
init_pxl_font_file(font_fp, fontptr)
FILE *font_fp;
struct font_entry *fontptr;
{
int t, i;
register struct char_entry *tcharptr;
/*
* Read the PXL file
*/
if((t = get_unsigned(font_fp, 4)) != PXLID)
{
message("Bad font file version %d; font %s.",
t, fontptr->name);
fclose(fontptr->font_file_fd);
fontptr->font_file_fd = NO_FILE;
return TRUE;
}
fseek(font_fp, -20L, 2);
t = get_unsigned(font_fp, 4);
if((fontptr->c != 0) && (t != 0) && (fontptr->c != t))
message("Bad font checksum %d != %d; font %s.",
t, fontptr->c, fontptr->name);
fontptr->magnification = get_unsigned(font_fp, 4);
fontptr->designsize = get_unsigned(font_fp, 4);
fseek(font_fp, (long)get_unsigned(font_fp, 4) * 4, 0);
for(i = 0; i < NPXLCHARS; i++)
{
tcharptr = &(fontptr->ch[i]);
tcharptr->width = get_unsigned(font_fp, 2);
tcharptr->height = get_unsigned(font_fp, 2);
tcharptr->xOffset= get_signed(font_fp, 2);
tcharptr->yOffset = get_signed(font_fp, 2);
tcharptr->where.isloaded = FALSE;
tcharptr->where.address.fileOffset =
get_unsigned(font_fp, 4) * 4;
tcharptr->tfmw =
((float)get_unsigned(font_fp, 4)*(float)fontptr->s) /
(float)(1<<20);
}
/*
* Return leaving font file open for access.
*/
return TRUE;
}
static u_char bit_mask[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
/*
* read_font_char:
* Reads character from font file.
* Returns TRUE unless document cannot be processed.
*/
/* ARGSUSED */
bool
read_pxl_font_char(font_fp, fontptr, ptr)
FILE *font_fp;
struct font_entry *fontptr;
register struct char_entry *ptr;
{
register struct pixrect *pr;
register int i, j, nints, nbytes, bp;
u_int buf;
/*
* Seek to start of char.
*/
fseek(font_fp, (long)ptr->where.address.fileOffset, 0);
/*
* Create a mem pixrect.
* Read the char.
*/
pr = mem_create(ptr->width, ptr->height, 1);
nints = (ptr->width + 31) >> 5;
pr_rop(pr, 0, 0, ptr->width, ptr->height, PIX_CLR, NULL, 0, 0);
bp = 0;
for (i=0; i < ptr->height; i++) {
nbytes = nints * 4;
for (j=0; j<ptr->width; j++) {
if(!(bp & 7)) {
buf = getc(font_fp);
nbytes--;
}
pr_put(pr, j, i, (buf & bit_mask[bp&7])?1:0);
bp++;
}
while (nbytes--)
getc(font_fp);
bp = 0;
}
ptr->where.address.pixrectptr = pr;
ptr->where.isloaded = TRUE;
return TRUE;
}
/*
* PK font reading functions
*/
/* ID byte value at the beginning of PK files */
#define PK_ID 89
/* PK op codes */
#define PK_XXX1 240
#define PK_XXX2 241
#define PK_XXX3 242
#define PK_XXX4 243
#define PK_YYY 244
#define PK_POST 245
#define PK_NOP 246
#define PK_PRE 247
#define PK_REPEAT 0xe /* Repeat last row - repeat count in next nibble */
#define PK_AGAIN 0xf /* Repeat only once */
#define PK_LARGE 0x0 /* Long run vaule coming up */
/*
* the macros that read pk values need these variables.
*/
static u_short _nyb_buf,
_nyb_flag,
_pk_repeat;
/*
* get the next nybble of the file. This macro requires
* that 2 integers named _nyb_buf and _nyb_flag be allocated elsewhere in
* the program. In addition, _nyb_flag must be initialized to 0.
*/
#define GET_NYB ((_nyb_flag ^= 1) ? \
((_nyb_buf = (unsigned)getc(font_fp)) >> 4) : \
(_nyb_buf & 0xf))
/*
* The quantity to be packed into nybbles may require an odd number of
* nybbles which will cause the nybble fetching macro to get out of
* sync. The following macro ``clears'' the state of the nybble fetching
* routine and should be executed whenever transitioning from nybble to
* byte (or other) quantities.
*/
#define CLEAR_NYB _nyb_flag = 0;
/*
* this macro gets a PK ``packed number'' from fp and puts it into x.
* It is an adaption of an algorithm presented in Tugboat V. 6, No. 3.
*/
#define GET_PACKED(x) x = get_packed(font_fp, dyn_f)
static u_int
get_packed(font_fp, dyn_f)
register FILE *font_fp;
register u_int dyn_f;
{
register int i, j;
i = GET_NYB;
if (i == 0) {
/*
* we have an arbitrarily long number. scan to
* find the first non-zero nybble which is the
* count of the nybbles in this value.
*/
do {
j = GET_NYB;
i++;
} while (j == 0);
while (--i >= 0)
j = (j << 4) + GET_NYB;
return (j + 193 - 15 * dyn_f);
} else if (i <= dyn_f) {
/* this nybble is the number we want. */
return (i);
} else if (i < 14) {
return (i + 15 * (i - dyn_f - 1) + GET_NYB);
} else if (i == 14) {
_pk_repeat = get_packed (font_fp, dyn_f);
} else {
_pk_repeat = 1;
}
return (i);
}
bool
init_pk_font_file (font_fp, fontptr)
register FILE *font_fp;
register struct font_entry *fontptr;
{
register unsigned c, cc;
long pl, addr;
register u_int i;
u_int hppp, vppp;
int checksum;
u_int tfmw;
double cscale;
fseek (font_fp, 0L, 0); /* make sure at the beginning of pk file */
if (get_unsigned(font_fp, 1) != PK_PRE) {
message("pk font file %s doesn't start with PRE\n",
fontptr->name);
fclose(fontptr->font_file_fd);
fontptr->font_file_fd = NO_FILE;
return TRUE;
}
if (get_unsigned(font_fp, 1) != PK_ID) {
message("pk font file %s wrong version\n",
fontptr->name);
fclose(fontptr->font_file_fd);
fontptr->font_file_fd = NO_FILE;
return TRUE;
}
fseek (font_fp, (long) get_unsigned(font_fp, 1), 1); /* skip comment */
fontptr->designsize = get_unsigned(font_fp, 4); /* ds[4] */
checksum = get_unsigned(font_fp, 4); /* checksum[4] */
hppp = get_unsigned(font_fp, 4); /* hppp[4] */
vppp = get_unsigned(font_fp, 4); /* vppp[4] */
cscale = (double) fontptr->s / (double)(1 << 20);
while ((c = get_unsigned(font_fp, 1)) != EOF) {
if (c >= PK_XXX1) { /* commands are just skipped */
switch (c) {
case PK_XXX1: /* pk_xxx1 k[1] x[k] */
fseek (font_fp, (long)get_unsigned(font_fp,1), 1);
break;
case PK_XXX2: /* pk_xxx2 k[2] x[k] */
fseek (font_fp, (long)get_unsigned(font_fp,2), 1);
break;
case PK_XXX3: /* pk_xxx3 k[3] x[k] */
fseek (font_fp, (long)get_unsigned(font_fp,3), 1);
break;
case PK_XXX4: /* pk_xxx4 k[4] x[4] */
fseek (font_fp, (long)get_signed(font_fp,4), 1);
break;
case PK_YYY: /* pk_yyy y[4] */
(void) get_unsigned(font_fp, 4);
break;
case PK_POST:
return TRUE;
case PK_PRE:
message("pk font file %s has extra PRE\n",
fontptr->name);
fclose(fontptr->font_file_fd);
fontptr->font_file_fd = NO_FILE;
return TRUE;
default: /* do nothing */ ;
}
} else { /* flag byte */
switch (c & 0x07) { /* check flag byte */
case 0:/* short form */
case 1:
case 2:
case 3:
/* length */
pl = (long) get_unsigned(font_fp, 1)
+ (long) ((c & 0x03) << 8);
cc = get_unsigned(font_fp,1); /* char. code */
tfmw = get_unsigned(font_fp,3); /* tfm width */
(void) get_unsigned(font_fp,1); /* x-escapement */
fontptr->ch[cc].width = get_unsigned(font_fp, 1);
fontptr->ch[cc].height = get_unsigned(font_fp, 1);
fontptr->ch[cc].xOffset = get_signed(font_fp, 1);
fontptr->ch[cc].yOffset = get_signed(font_fp, 1);
addr = ftell (font_fp);
pl -= 8;
break;
case 4:/* extended short form */
case 5:
case 6:
pl = (long) get_unsigned(font_fp, 2)
+ (long) ((c & 0x03) << 16);
cc = get_unsigned(font_fp,1); /* char. code */
tfmw = get_unsigned(font_fp,3); /* tfm width */
(void) get_unsigned(font_fp,2); /* x-escapement */
fontptr->ch[cc].width = get_unsigned(font_fp, 2);
fontptr->ch[cc].height = get_unsigned(font_fp, 2);
fontptr->ch[cc].xOffset = get_signed(font_fp, 2);
fontptr->ch[cc].yOffset = get_signed(font_fp, 2);
addr = ftell (font_fp);
pl -= 13;
break;
case 7:/* long form */
pl = get_unsigned(font_fp,4);
cc = get_unsigned(font_fp,4); /* char. code */
tfmw = get_unsigned(font_fp,4);
(void) get_unsigned(font_fp,4); /* x-escapement */
fontptr->ch[cc].width = get_unsigned(font_fp, 4);
fontptr->ch[cc].height = get_unsigned(font_fp, 4);
fontptr->ch[cc].xOffset = get_signed(font_fp, 4);
fontptr->ch[cc].yOffset = get_signed(font_fp, 4);
addr = ftell (font_fp);
pl -= 24;
break;
}
fontptr->ch[cc].tfmw = (int)(((double)tfmw * cscale) + 0.5);
fontptr->ch[cc].where.isloaded = 0;
fontptr->ch[cc].where.flags = c;
fontptr->ch[cc].where.address.fileOffset = addr;;
fseek (font_fp, pl, 1); /* skip until next flag byte */
}
}
if((fontptr->c != 0) && (checksum != 0) && (fontptr->c != checksum))
message("Bad font checksum %d != %d; font %s.",
checksum, fontptr->c, fontptr->name);
return TRUE;
}
/*
* load a PK character into memory.
*/
bool
read_pk_font_char(font_fp, fontptr, ptr)
register FILE *font_fp;
register struct font_entry *fontptr;
register struct char_entry *ptr;
{
register struct pixrect *pr;
int cw; /* character width */
int ch; /* character height */
u_int dyn_f; /* dynamic factor, part of a PK word. */
register int i, j;
register int black, bits, bp, rc;
int rowp;
if (ptr->width == 0 || ptr->height == 0) {
ptr->where.address.pixrectptr = (struct pixrect *) 0;
return;
}
fseek(font_fp, (long)ptr->where.address.fileOffset, 0);
pr = mem_create(ptr->width, ptr->height, 1);
ptr->where.address.pixrectptr = pr;
cw = ptr->width; ch = ptr->height;
pr_rop(pr, 0, 0, cw, ch, PIX_CLR, NULL, 0, 0);
/*
* what remains is the data for the image. It can be packaged
* either as a run-encoding where successive values are the
* number of adjacent pixels to paint in the opposite color of
* the previous painting, or simply as a bitmap with no padding
* except (possibly) for the very last nybble to round up to a
* byte value.
*
* the data for the character is stored in successive bits with
* each new horizontal row at a long boundary. See the PXL
* file format.
*/
/*
* grab the dyn_f out of the flag for this character.
*/
dyn_f = (ptr->where.flags >> 4) & 0xf;
/*
* the data returned by calloc is zeroed; we depend on that
* because we only turn on bits that are supposed to be
* black.
*/
if (dyn_f == 14) {
/*
* we have a bitmap rather than a run-encoding.
*/
u_int buf;
bp = 0;
for (i=0; i < ch; i++) {
for (j=0; j<cw; j++) {
if(!(bp & 7))
buf = getc(font_fp);
pr_put(pr, j, i, (buf & bit_mask[bp&7])?1:0);
bp++;
}
}
} else {
bp = _pk_repeat = rc = rowp = 0;
black = ptr->where.flags & (1 << 3);
bits = cw * ch;
CLEAR_NYB;
while (bp < bits) {
GET_PACKED(j);
if (_pk_repeat != 0) {
rc = _pk_repeat;
rowp = bp / cw;
_pk_repeat = 0;
continue;
}
/*
* we have a run count in j.
*/
if (black) {
register int k,l,m;
l = bp / cw; /* starting row */
m = (bp + j) / cw; /* ending row */
k = bp % cw; /* start bit offset */
i = (bp + j) % cw; /* ending bit offset */
if (j <= cw && (k < i || i == 0)) {
/* we're changing less than a row */
pr_rop(pr, k, l, j, 1, PIX_SET,
NULL, 0, 0);
} else {
/* fill any fragment in the current row */
pr_rop(pr, k, l, cw-k, 1, PIX_SET,
NULL, 0, 0);
/* fill some number of full rows */
pr_rop(pr, 0, l+1, cw, (j-(cw-k))/cw,
PIX_SET, NULL, 0, 0);
/* fill any fragment in the last row */
if (i)
pr_rop(pr, 0, m, i, 1, PIX_SET,
NULL, 0, 0);
}
}
bp += j;
/*
* if there's a repeat count and we hit the end of
* a row, do the copy.
*/
if (rc && (bp - (rowp*cw)) >= cw) {
i = rowp+1;
j = rowp+1+rc;
if ((i*cw) != bp) {
pr_rop(pr, 0, j, cw, 1, PIX_SRC,
pr, 0, i);
}
j = rc;
while(j--) {
pr_rop(pr, 0, i, cw, 1, PIX_SRC,
pr, 0, rowp);
i++;
}
bp += rc * cw;
rc = 0;
}
black = !black;
}
}
ptr->where.isloaded = TRUE;
return TRUE;
}